package com.jdk.learn.juc._03concurcontainer;

import java.util.*;

/**
 * Created by baiguantao on 2018/1/31.
 *  concurentHashMap 在1.8之前采用的是锁分段机制
 *      即 每段持有锁，粒度降低，并发支持增强  每段中是链表
 *      1.8之后使用了cas方式，且增加了红黑树的支持。
 * 并发容器
 Java 5.0 在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器
 的性能。
  ConcurrentHashMap 同步容器类是Java 5 增加的一个线程安全的哈希表。对
 与多线程的操作，介于 HashMap 与 Hashtable 之间。内部采用“锁分段”
 机制替代 Hashtable 的独占锁。进而提高性能。
  此包还提供了设计用于多线程上下文中的 Collection 实现：
 ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、
 CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给
 定 collection 时，ConcurrentHashMap 通常优于同步的 HashMap，
 ConcurrentSkipListMap 通常优于同步的 TreeMap。当期望的读数和遍历远远
 大于列表的更新数时，CopyOnWriteArrayList 优于同步的 ArrayList。

 */
public class TestCopyOnWriteList {
    public static void main(String[] args) {

        HelloConcurList hcl=new HelloConcurList();

        for (int i = 0; i < 5; i++) {
            new Thread(hcl).start();
        }

        System.out.println("");
    }
}

class HelloConcurList implements Runnable {

    /**
     * 常规手段  使用此种方式 sts.add("AA");会有并发修改异常
     * */
    private static List<String> sts= Collections.synchronizedList(new ArrayList<String>());

    /**
     * 解决方案是使用CopyOnWriteArrayList
     * 当有写入的时候进行复制   适合遍历多的情况，不太适合写入操作多的情况，性能比较低下
     * 而且终止的时间不定  可能执行的多，即add的很多，也可能add了很少就线程结束了。
     */
//    private static List<String> sts= new CopyOnWriteArrayList<>();

    static{
        sts.add("aa");
        sts.add("aa1");
        sts.add("aa2");
    }
    @Override
    public void run() {
        Iterator<String> iterator = sts.iterator();
        while (iterator.hasNext()){
            /**
             * java.util.ConcurrentModificationException
             at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
             at java.util.ArrayList$Itr.next(ArrayList.java:851)
             at com.jdk.learn.juc._03concurcontainer.HelloConcurList.run(TestCopyOnWriteList.java:57)
             at java.lang.Thread.run(Thread.java:745)
             */
            System.out.println(iterator.next());//添加后 next检查异常 即并发可能写入，但是个线程数据不同步
            sts.add("AA");
            System.out.println(Thread.currentThread().getName()+":"+sts.size()+":---"+sts);
            if (sts.size()>=100) {
                break;
            }
        }
    }
//    @Override
    public void run2() {
        ListIterator<String> stringListIterator = sts.listIterator();
        while (stringListIterator.hasNext()){
            System.out.println(stringListIterator.next());
            stringListIterator.add("AA");
        }
    }
}

